using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.VisualStudio.Package;
using Microsoft.VisualStudio.Shell.Interop;
using System.Diagnostics;
using System.IO;
using Microsoft.VisualStudio;

namespace NBusiness.VisualStudio
{
    public class ESharpDependentFileNode : DependentFileNode
    {
        public ESharpDependentFileNode(ProjectNode root, ProjectElement element)
            : base(root, element)
        { }
        
        protected override FileNode RenameFileNode(string oldFileName, string newFileName, uint newParentId)
        {
            if (string.Compare(oldFileName, newFileName, StringComparison.InvariantCulture) == 0)
            {
                // We do not want to rename the same file
                return null;
            }

            //Clean up all this crud
            this.OnItemDeleted();
            this.Parent.RemoveChild(this);

            // Since this node has been removed all of its state is zombied at this point
            // Do not call virtual methods after this point since the object is in a deleted state.

            string[] file = new string[1];
            file[0] = newFileName;
            VSADDRESULT[] result = new VSADDRESULT[1];
            Guid emptyGuid = Guid.Empty;
            ErrorHandler.ThrowOnFailure(this.ProjectMgr.AddItemWithSpecific(newParentId, VSADDITEMOPERATION.VSADDITEMOP_OPENFILE, null, 0, file, IntPtr.Zero, 0, ref emptyGuid, null, ref emptyGuid, result));

            FileNode childAdded = this.ProjectMgr.FindChild(newFileName) as FileNode;
            Debug.Assert(childAdded != null, "Could not find the renamed item in the hierarchy");
            // Update the itemid to the newly added.
            this.ID = childAdded.ID;

            // Remove the item created by the add item. We need to do this otherwise we will have two items.
            // Please be aware that we have not removed the ItemNode associated to the removed file node from the hierrachy.
            // What we want to achieve here is to reuse the existing build item. 
            // We want to link to the newly created node to the existing item node and addd the new include.

            //temporarily keep properties from new itemnode since we are going to overwrite it
            string newInclude = childAdded.ItemNode.Item.Include;
            string dependentOf = childAdded.ItemNode.GetMetadata(ProjectFileConstants.DependentUpon);
            childAdded.ItemNode.RemoveFromProjectFile();

            // Assign existing msbuild item to the new childnode
            childAdded.ItemNode = this.ItemNode;
            childAdded.ItemNode.Item.Name = this.ItemNode.ItemName;
            childAdded.ItemNode.Item.Include = newInclude;

            FileNode node = childAdded;
            if (!string.IsNullOrEmpty(dependentOf) &&
                newInclude.StartsWith(Path.GetFileNameWithoutExtension(dependentOf)))
            {
                childAdded.ItemNode.SetMetadata(ProjectFileConstants.DependentUpon, dependentOf);
            }
            else
            {
                childAdded.ItemNode.SetMetadata(ProjectFileConstants.DependentUpon, null);
                HierarchyNode newParent = childAdded.Parent.Parent;
                childAdded.Parent.RemoveChild(childAdded);

                //Move the item up if it's name isn't a subset of the parents anymore.
                if (newParent != null)
                {
                    ESharpFileNode independent = new ESharpFileNode(this.ProjectMgr, childAdded.ItemNode);
                    newParent.AddChild(independent);
                    HierarchyNode hn = childAdded.FirstChild;
                    while (hn != null)
                    {
                        node.AddChild(hn);
                        hn = hn.NextSibling;
                    }
                    node = independent;
                    node.ID = childAdded.ID;
                }
            }

            node.ItemNode.RefreshProperties();

            //Update the new document in the RDT.
            DocumentManager.RenameDocument(this.ProjectMgr.Site, oldFileName, newFileName, node.ID);

            //Select the new node in the hierarchy
            IVsUIHierarchyWindow uiWindow = UIHierarchyUtilities.GetUIHierarchyWindow(this.ProjectMgr.Site, SolutionExplorer);
            uiWindow.ExpandItem(this.ProjectMgr, this.ID, EXPANDFLAGS.EXPF_SelectItem);

            //Update FirstChild
            node.FirstChild = this.FirstChild;

            //Update ChildNodes
            SetNewParentOnChildNodes(node);
            RenameChildNodes(node);

            return node;
        }
    }
}
